/**
 * Created by Wade (weida1985@163.com) on 2018/10/17.
 */
require('colors')
let mysql = require('mysql')
let async = require('async')
let pool = null

function createPool(config) {
    pool = mysql.createPool(config)
    // console.info('sqlClient.js mysql.createPool()\n', config)
}

function getPool() {
    return pool
}

// 并发数不能超过最大连接数量 @return promise
function exec(sqlStr, isSingle = false, sqlParams = false, successCallback, failureCallback) {
    return new Promise((resolve, reject) => {
        pool.getConnection((cErr, conn) => {
            if (cErr) {
                console.error('SQL CONNECT ERROR', cErr)
                if (failureCallback) {
                    failureCallback(cErr)
                }
                reject(cErr)
            } else {
                // console.info('SQL EXECUTE: ----------- \n', sqlStr)
                let connection = conn
                connection.query(sqlStr, sqlParams, (qErr, results) => {
                    connection.release()
                    if (qErr) {
                        console.warn('SQL EXECUTE ERROR', qErr)
                        // 回调中如果不控制，不进行打断
                        if (failureCallback && failureCallback(qErr)) {
                            return
                        }
                    }

                    console.info(('[SQL]: ' + sqlStr).green, ('\n[RESULT]: ' + JSON.stringify(results/*, null, 2*/)).blue)

                    // console.info('mysql-result:\n', JSON.stringify(results, null, 2))
                    if (successCallback) {
                        successCallback(results)
                    }
                    if (isSingle) {
                        resolve(results ? results[0] : undefined)
                    }
                    resolve(results)
                })
            }
        })
    })
}

// 事务
function execTrans(sqlArray, callback) {
    pool.getConnection(function (err, connection) {
        if (err) {
            return callback(err, null)
        }
        connection.beginTransaction(function (err) {
            if (err) {
                return callback(err, null)
            }
            console.log(`开始执行transaction，共执行${sqlArray.length}条数据`)
            let funcArray = sqlArray.map(sqlCfg => cb => {
                let sql = sqlCfg.sql
                let param = sqlCfg.params
                console.info(('[SQL]: ' + sql).green + ('\n[PARAM]: ' + JSON.stringify(sqlCfg.params)).blue)
                connection.query(sql, param, (tErr, rows, fields) => {
                    if (tErr) {
                        connection.rollback(() => {
                            console.log(`事务失败，${param}, ERROR：${tErr}`)
                            callback(tErr, null)
                            throw tErr
                        })
                    } else {
                        return cb(null, 'ok')
                    }
                })
            })

            async.series(funcArray, function (err, result) {
                if (err) {
                    connection.rollback(function (err) {
                        console.log(`transaction error: ${err}`)
                        connection.release()
                        return callback(err, null)
                    })
                } else {
                    connection.commit(function (err, info) {
                        console.log(`transaction info: ${JSON.stringify(info)}`)
                        if (err) {
                            console.log(`执行事务失败， ${err}`)
                            connection.rollback(function (err) {
                                console.log(`transaction error: ${err}`)
                                connection.release()
                                return callback(err, null)
                            })
                        } else {
                            connection.release()
                            return callback(null, info)
                        }
                    })
                }
            })
        })
    })
}

process.on('uncaughtException', function (err) {
    console.error(err)
})

exports.exec = exec
exports.execTrans = execTrans
exports.createPool = createPool
exports.getPool = getPool
exports.escape = mysql.escape
